<?php
/**
 * This file is part of Hyperf Mall.
 *
 * @link     https://gitee.com/scwlkj/hyperf_mall
 * @contact  hyperf_mall@163.com
 */

declare(strict_types=1);

namespace App\Cache;

use App\Common\DataConvert;
use App\Common\Singleton;
use Hyperf\Redis\Redis;
use Hyperf\Utils\ApplicationContext;
use Psr\Container\ContainerExceptionInterface;
use Psr\Container\NotFoundExceptionInterface;

abstract class BaseCache
{
    use Singleton;

    protected static $redis;

    protected $data;

    /**
     * 缓存key
     * @var string
     */
    protected static $cacheKey;

    /**
     * 缓存过期时间(秒) 0为永久保存
     * @var int
     */
    protected static $cacheExpire = 0;

    /**
     * @throws ContainerExceptionInterface
     * @throws NotFoundExceptionInterface
     */
    public function __construct()
    {
        $container = ApplicationContext::getContainer();
        self::$redis = $container->get(Redis::class);
        $this->loadData();
    }

    public function loadData()
    {
        $data = self::$redis->get($this->getCacheKey());
        if (empty($data)) { //没有数据，自动加载
            $this->load();
            return;
        }

        $this->data = DataConvert::decode($data);
    }

    /**
     * Notes:加载数据
     */
    public function load()
    {
        $this->data = $this->formatDataFromModel($this->loadFromModel());
        $this->saveToCache();
    }

    /**
     * Notes:保存数据
     */
    public function saveToCache()
    {
        if (static::$cacheExpire <= 0) { //永久保存
            self::$redis->set($this->getCacheKey(), DataConvert::encode($this->data));
        } else {
            self::$redis->setex($this->getCacheKey(), static::$cacheExpire, DataConvert::encode($this->data));
        }
    }

    /**
     * 通过key获取数据
     * @param string|int|null $key
     * @return mixed
     */
    public function get($key = null)
    {
        if ($key === null) {
            return $this->data;
        }

        return $this->data[$key] ?? null;
    }

    /**
     * Notes:删除缓存
     */
    public function deleteCache()
    {
        self::$redis->del($this->getCacheKey());
    }

    /**
     * Notes: 处理key
     * @return string
     */
    public function getCacheKey(): string
    {
        return get_saas_id() . ':' . static::$cacheKey ;
    }

    /**
     * 从模型中加载
     * @return mixed
     */
    abstract public function loadFromModel();

    /**
     * 检查数据并格式化
     * @param mixed $data
     * @return mixed
     */
    abstract public function formatDataFromModel($data);
}
